package com.perfma.xtest.cmd;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;


public class JobThread extends Thread {
    private static Logger logger = LoggerFactory.getLogger(JobThread.class);

    private Long jobId;
    private IJobHandler handler;
    private LinkedBlockingQueue<TriggerParam> triggerQueue;
    private ConcurrentHashMap<Long, Long> triggerLogIdMap;

    private boolean toStop = false;
    private String stopReason;

    private boolean running = false;
    private int idleTimes = 0;

    public JobThread() {
        this.triggerQueue = new LinkedBlockingQueue<TriggerParam>();
        this.triggerLogIdMap = new ConcurrentHashMap<>();
    }


    /**
     * new trigger to queue
     *
     * @param triggerParam
     * @return
     */
    public ReturnT<String> pushTriggerQueue(TriggerParam triggerParam) {
        if (triggerLogIdMap.containsKey(triggerParam.getJobId())) {
            logger.error("任务重复执行, 任务ID为:{}", triggerParam.getJobId());
            return new ReturnT<String>(ReturnT.FAIL_CODE, "任务重复执行, 任务ID为:" + triggerParam.getJobId());
        }
        if (triggerParam.getCallBackBiz() == null) {
            logger.error("任务-{},未指定任务回调线程", triggerParam.getJobId());
            throw new JobException("未指定任务回调");
        }
        this.toStop = false;
        IJobHandler jobHandler = new ScriptJobHandler(triggerParam.getJobId(), System.currentTimeMillis(),
                triggerParam.getGlueSource(), triggerParam.getEnv());
        this.jobId = triggerParam.getJobId();
        this.handler = jobHandler;
        triggerQueue.add(triggerParam);
        return ReturnT.SUCCESS;
    }

    /**
     * kill job thread
     * hread.interrupt只支持终止线程的阻塞状态(wait、join、sleep)，
     * 在阻塞出抛出InterruptedException异常,但是并不会终止运行的线程本身
     *
     * @param stopReason
     */
    public void toStop(String stopReason) {
        this.toStop = true;
        this.stopReason = stopReason;
    }

    /**
     * is running job
     *
     * @return
     */
    public boolean isRunningOrHasQueue() {
        return running || triggerQueue.size() > 0;
    }

    @Override
    public void run() {
        while (!toStop) {
            running = false;
            idleTimes++;
            try {
                // to check toStop signal, we need cycle, so wo cannot use queue.take(), instand of poll(timeout)
                TriggerParam triggerParam = triggerQueue.poll(2L, TimeUnit.SECONDS);
                if (triggerParam != null) {
                    running = true;
                    idleTimes = 0;
                    triggerLogIdMap.remove(triggerParam.getJobId());
                    // handle job
                    ReturnT<String> executeResult = null;
                    try {
                        String logFileName = JobFileAppender.makeLogFileName(triggerParam.getJobId());

                        JobFileAppender.contextHolder.set(logFileName);

                        executeResult = handler.execute();
                        if (executeResult == null) {
                            executeResult = ReturnT.FAIL;
                        }
                        JobLogger.log("任务执行完毕,执行结果为:" + executeResult);
                    } catch (Exception e) {
                        if (toStop) {
                            JobLogger.log("执行器被停止, 原因为:" + stopReason);
                        }
                        logger.error("[执行器] 任务ID:{} 任务执行发生异常(失败) 异常信息:", triggerParam.getJobId(), e);
//
//                        StringWriter stringWriter = new StringWriter();
//                        e.printStackTrace(new PrintWriter(stringWriter));
//                        String errorMsg = stringWriter.toString();
//                        executeResult = new ReturnT<String>(ReturnT.FAIL_CODE, errorMsg);
//
//                        JobLogger.log("任务执行发生异常(失败) 异常信息:\n" + errorMsg);
                    }

                    //无论结果执行成功与否，都需要进行callback
                    HandleCallbackParam handleCallbackParam = new HandleCallbackParam(triggerParam.getJobId(), executeResult);
                    handleCallbackParam.setCallBackBiz(triggerParam.getCallBackBiz());
                    TriggerCallbackThread.pushCallBack(handleCallbackParam);


                    // common
                    ExecutorBizImpl.getScriptPool().remove(triggerParam.getJobId());
                    logger.info("移除任务:jobId=[{}]", triggerParam.getJobId());
                    JobExecutor.removeJobThread(triggerParam.getJobId(), "任务执行结束,停止当前执行器");

                } else {
                    if (idleTimes > 10) {
                        logger.info("[脚本执行器] 任务执行完毕 执行器空闲时间超时");
                        JobExecutor.removeJobThread(jobId, "执行器空闲时间超时");
                        this.toStop = true;
                    }
                }
            } catch (Throwable e) {
                if (toStop) {
                    JobLogger.log("执行器停止, 原因为:" + stopReason);
                }
                logger.error("[执行器] 任务执行发生异常(失败) 异常信息:", e);
//                StringWriter stringWriter = new StringWriter();
//                e.printStackTrace(new PrintWriter(stringWriter));
//                String errorMsg = stringWriter.toString();
//                JobLogger.log("任务执行发生异常 异常信息:" + errorMsg);
            }
        }
        logger.info("任务执行器程停止, 线程标示:{}", Thread.currentThread());
    }
}
